package cn.com.util;

import java.util.Random;

import com.ibm.icu.text.DecimalFormat;

public class HongBaoAlgorithm {
	
	static Random random = new Random();
	static {
		random.setSeed(System.currentTimeMillis());
	}
	
//	public static void main(String[] args) {
//		long max = 200_00;
//		long min = 20;
//		
//		long sumTotal = 0;
//		for(int i=0; i<100; i++)
//		{
//			long result = HongBaoAlgorithm.generate(10000_00, 100, max, min, i+1, sumTotal);
//			sumTotal = sumTotal + result;
//			System.out.println("result[" + i +"]: " + result);
//		}
//		
//		//检查生成的红包的总额是否正确
//		System.out.println("total:" + sumTotal);
//	}

	/**
	 * 
	 * @param total
	 *            红包总额
	 * @param count
	 *            红包个数
	 * @param max
	 *            每个小红包的最大额
	 * @param min
	 *            每个小红包的最小额
	 * @param userdCount
	 *            已领取有金额红包数
	 * @param usedMoney
	 *            已领取有金额红包总额
	 * @return 存放生成的每个小红包的值的数组
	 */
	public static float generate(long total, int count, long max, long min, int usedCount, long usedMoney) {
//		long[] result = new long[count];

		long average = total / count;

		long avaibleMoney = total-usedMoney;
		int avaibleCount = count - usedCount;
		
		long retValue = 0;

		//这样的随机数的概率实际改变了，产生大数的可能性要比产生小数的概率要小。
		//这样就实现了大部分红包的值在平均数附近。大红包和小红包比较少。
		
		//判断是否是最后一个红包
		if(avaibleCount == 1)
		{
			DecimalFormat df = new DecimalFormat("#.##");
			float retMoney = Float.parseFloat(df.format(Double.valueOf(avaibleMoney)/100)); 
			return retMoney;
		}else 
		{
			boolean checkState = true;
			//因为小红包的数量通常是要比大红包的数量要多的，因为这里的概率要调换过来。
			//当随机数>平均值，则产生小红包
			//当随机数<平均值，则产生大红包
			int rollTimes = 0;
			while(checkState)
			{
				
				if (nextLong(min, max) > average) {
					// 在平均线上减钱
	//				long temp = min + sqrt(nextLong(range1));
					retValue = min + xRandom(min, average);
//					System.out.println("======upper=======: " + nextLong(min, max));
//					avaibleMoney -= retValue;
				} else {
					// 在平均线下加钱
	//				long temp = max - sqrt(nextLong(range2));
					retValue = max - xRandom(average, (max-min));
//					System.out.println("======lower=======: " + nextLong(min, max));
//					avaibleMoney -= retValue;
				}
				
				//检查剩下的钱是否可以满足最小额发放数                                                                                                                                                                                                                                                                                                                                                                                                                        (检查已生成的金额是否大于总金额)
				long tempAverage = (avaibleMoney-retValue)/(avaibleCount - 1);
				
				if(tempAverage < min || tempAverage > max || (usedMoney + retValue) >= total || avaibleCount == 2)
				{
					//重新生成
					if(avaibleCount == 2)
					{
						if((avaibleMoney-retValue) >= max)
						{
							//最后第2次生成后剩下的金额比max大时，直接平均加成
							retValue = avaibleMoney/2 + nextLong(0, min);	
						}
						else if((avaibleMoney-retValue) < min) {
							retValue = avaibleMoney/2 + nextLong(0, min);
						}
						checkState = false;
					}else {
						rollTimes++;
						if(rollTimes > 1000)
						{
							retValue = nextLong(0, min)+min;
							checkState = false;
						}
						System.out.println("======rollTimes=======: " + rollTimes);
					}
					
				}else {
				
					checkState = false;
				}
				
			}
			DecimalFormat df = new DecimalFormat("#.##");
			float retMoney = Float.parseFloat(df.format(Double.valueOf(retValue)/100)); 
			System.out.println("======generate=======: " + retMoney);
			return retMoney;
		}
	}

	static long sqrt(long n) {
		// 改进为查表？
//		System.out.println("======sqrt=======: " + n);
		return (long) Math.sqrt(n);
	}

	static long sqr(long n) {
		// 查表快，还是直接算快？
		return n * n;
	}
	
	static long nextLong(long n) {
		
		if(n >= 2147483648L)
		{
			System.out.println("======nextLong new_n is out of scope=======: " + n);
			long temp = n/100000000;
			long rightData = n%100000000;
			return random.nextInt((int) temp)*100000000+rightData;
		}else {
			int len = String.valueOf(n).trim().length();
			long rightData = n%(long)Math.pow(10, len-2);
			long firstBit = (long)((n-rightData) / Math.pow(10, len-2));
			int tempRadom = random.nextInt((int) firstBit);
			long newRadom = (long)(tempRadom*Math.pow(10, len-2) + rightData);
			return newRadom;
		}
		
	}

	static long nextLong(long min, long max) {
		long new_min = min/100;
		long new_max = max/100;
		long ret = 100*(random.nextInt((int) (new_max - new_min + 1)) + new_min);
		System.out.println("======nextLong(long min, long max)=======: " + ret);
		return ret;
	}
	
	/**
	 * 生产min和max之间的随机数，但是概率不是平均的，从min到max方向概率逐渐加大。
	 * 先平方，然后产生一个平方值范围内的随机数，再开方，这样就产生了一种“膨胀”再“收缩”的效果。
	 * 
	 * @param min
	 * @param max
	 * @return
	 */
	static long xRandom(long min, long max) {
		System.out.println("======xRandom:min=======: " + min);
		System.out.println("======xRandom:max=======: " + max);
		long ret = sqrt(nextLong(sqr(max - min)));
		System.out.println("======xRandom:result=======: " + ret);
		return ret;
	}
}